package cz.data.domain.market.mapping.handler;

import com.alibaba.fastjson.JSONObject;
import cz.data.common.annotation.DataInner;
import cz.data.common.base.BaseResponse;
import cz.data.domain.market.mapping.handler.interceptor.TableApiRequestInterceptor;
import cz.data.domain.market.mapping.service.impl.TableApiEngine;
import cz.data.domain.market.model.dto.TableApiSettings;
import cz.data.domain.market.model.entity.TableApiEntity;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@Component
public class TableApiRequestHandler {

    @Resource
    TableApiRequestInterceptor interceptor;
    @Resource
    TableApiEngine apiEngine;

    @SneakyThrows
    @ResponseBody
    public Object invoke(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                         @PathVariable(required = false) Map<String, Object> pathVariables,
                         @RequestParam(required = false) Map<String, Object> requestParams,
                         @RequestHeader(required = false) Map<String, Object> requestHeaders,
                         @RequestBody(required = false) Map<String, Object> requestBodys) {
        TableApiEntity tableApi = TableApiHandlerMapping.getMappingApiInfo(httpServletRequest);
        String access = Optional.ofNullable(tableApi)
                .map(TableApiEntity::getSettings)
                .map(TableApiSettings::getAccess)
                .orElse(DataInner.Access.authenticated.getValue());
        interceptor.authorization(httpServletRequest, access);
        Objects.requireNonNull(tableApi, "错误!API接口访问错误");
        boolean signValidate = interceptor.signValidate(httpServletRequest, tableApi, requestParams, requestHeaders, requestBodys);
        if (!signValidate) {
            return BaseResponse.error(500, "签名检验错误");
        }
        BaseResponse response = BaseResponse.error(500, "非标准接口格式");
        JSONObject params = null;
        long startTimeMillis = System.currentTimeMillis();
        try {
            String uri = httpServletRequest.getRequestURI();
            HttpMethod method = HttpMethod.resolve(httpServletRequest.getMethod());
            if (method == HttpMethod.GET) {
                if (StringUtils.endsWithIgnoreCase(uri, "/page")) {
                    params = new JSONObject(requestParams);
                    response = apiEngine.pageOperate(tableApi, params);
                } else {
                    Assert.notEmpty(pathVariables, String.format("详情%s缺少主键参数", uri));
                    params = new JSONObject(pathVariables);
                    response = apiEngine.getByIdOperate(tableApi, params);
                }
            } else if (method == HttpMethod.POST) {
                Assert.notEmpty(requestBodys, String.format("新增%s缺少请求体参数", uri));
                params = new JSONObject(requestBodys);
                response = apiEngine.insertOperate(tableApi, params);
            } else if (method == HttpMethod.PUT) {
                Assert.notEmpty(requestBodys, String.format("新增%s缺少请求体参数", uri));
                params = new JSONObject(requestBodys);
                response = apiEngine.updateOperate(tableApi, params);
            } else if (method == HttpMethod.DELETE) {
                Assert.notEmpty(pathVariables, String.format("详情%s缺少主键参数", uri));
                params = new JSONObject(pathVariables);
                response = apiEngine.removeOperate(tableApi, params);
            }
            interceptor.postLogHandle(startTimeMillis, httpServletRequest, tableApi, params, null, response);
        } catch (Exception e) {
            log.error("表数据接口调用错误: {}", e.getMessage());
            response = BaseResponse.error(500, e.getMessage());
            interceptor.postLogHandle(startTimeMillis, httpServletRequest, tableApi, params, e, response);
        }
        return response;
    }
}
